"""
@File    :   get_sqlalchemy_model_info.py
@Time    :   2024/04/07 15:33:59
@Author  :   Qrj
@Email   :   923207736@qq.com
@description   :   sqlalchemy模型的信息的工具类
"""

import re
from functools import lru_cache
from typing import Type

from sqlalchemy.exc import IntegrityError

from src.models.models import OrmBase
from src.typings import RequestValidationErrorConvertedDataT

from .auto_import import AutoImportUtil
from .path import PathUtil


class GetSqlalchemyModelInfoUtil:
    """获取sqlalchemy模型的信息的工具类"""

    @staticmethod
    @lru_cache
    def get_models_tablename_class_mappings() -> dict[str, Type[OrmBase]]:
        """获取所有sqlalchemy模型的表名与class的映射

        Returns:
            list[Type[OrmBase]]: 所有sqlalchemy模型的class列表
        """
        return {
            v.__tablename__: v
            for _, v in AutoImportUtil.auto_import_orm_model(
                PathUtil.get_project_root_path(), PathUtil.get_business_path()
            )
        }


class SqlalchemyIntegrityErrorUtil:
    """处理sqlalchemy完整性错误的工具类"""

    # 错误信息的匹配模式
    error_data_pattern = re.compile(r"for key \'(\S+)\'")

    @staticmethod
    def error_data_convert(exc: IntegrityError) -> RequestValidationErrorConvertedDataT:
        """错误信息转换

        Args:
            exc (IntegrityError): 错误信息
        """
        exc_err_msg = exc.args[0]
        pattern_info = SqlalchemyIntegrityErrorUtil.error_data_pattern.search(
            exc_err_msg
        )
        if pattern_info:
            # 拆分出表名与表字段名称
            table_name, err_field = pattern_info.group(1).split(".")
            # 获取所有sqlalchemy模型的表名与class的映射
            models_tablename_class_mappings = (
                GetSqlalchemyModelInfoUtil.get_models_tablename_class_mappings()
            )
            if table_name in models_tablename_class_mappings.keys():
                # 当有找到对应的表时, 再去找表下的字段
                model_class = models_tablename_class_mappings[table_name]
                err_field_obj = getattr(model_class, err_field, None)
                if err_field_obj:
                    # 有找到表下的字段
                    err_field_obj_comment = getattr(err_field_obj, "comment", None)
                    if err_field_obj_comment:
                        # 如果有从sqlalchemy模型中找到字段, 且字段有comment
                        # 则使用字段的comment信息构建字段已存在(重复)的错误信息
                        err_message = f"{err_field_obj_comment}已存在"
                    else:
                        # 否则还是用原来的英文字段名来构建错误信息
                        err_message = f"{err_field}已存在"
                else:
                    # 没有找到表下的字段
                    err_message = f"未知的表字段存在完整性错误(表与字段信息: {table_name} > {err_field})"
        else:
            # 没有匹配到表名与字段信息
            err_field = "unknown"
            err_message = f"未知的表的字段存在完整性错误(错误信息: {exc_err_msg})"

        return {
            err_field: {
                "err_type": "sqlalchemy_integrity_error",
                "err_message": err_message,
            },
        }
